/*
 * File:   fe.h
 * Author: boyan
 *
 * Created on December 11, 2007, 10:17 AM
 */

#include "glodef.h"
#include "grid3d.h"
#include "vecs.h"



#ifndef _FE_H
#define	_FE_H

#define NUM_FE   5

enum
{
    fe_p1=0, fe_p1_vec, fe_cr, fe_bub, fe_bub_vec
};

extern char const * const fe_long_names[NUM_FE];

extern char const * const fe_names[NUM_FE];

/* maximum number of local degrees of freedom */
#define MAX_LDOFS   15


#ifdef	__cplusplus
extern "C"
{
#endif


    void InitFE(int ntypes, const unsigned *types, grid3d_t *grid);
    void DoneFE(grid3d_t *grid);

    /* returns the number of degrees of freedom */
    int fe_ndof(const grid3d_t *grid, unsigned type);
    void fe_dof_coord(const grid3d_t *grid, node_t *nodes, unsigned type,
        int dof, double ** coords);
    unsigned fe_dof_bcond(const grid3d_t *grid, unsigned type, int dof);
    unsigned fe_dof_bdry(const grid3d_t *grid, unsigned type, int dof);

    int fe_global_basis(const grid3d_t *grid, node_t *nodes, int el,
        unsigned type, const double *Pt, double **basis);

    /* returns number of nodes, fills nodes with global nodes indices. */
    int fe_nodes(const grid3d_t *grid, int el, unsigned type, int **nodes);
    /* returns number of unknowns of element and fills an array of indices of unknowns */
    int fe_dofs(const grid3d_t *grid, int el, unsigned type, int **dofs);

    typedef void local_matr_t(const grid3d_t *grid, int el, unsigned type, double ***S);
    local_matr_t local_mass, local_stif, local_rot_rot, local_grad_div;

    void local_advm(const grid3d_t *grid, int el, unsigned type, vector A, double ***M);
    void local_advm_D(const grid3d_t *grid, int el, unsigned type, vector A, double ***M);
    void local_adjoit_B(const grid3d_t *grid, int el, unsigned type, vector A, double ***M);
    void local_adjoit_C(const grid3d_t *grid, int el, unsigned type, vector A, double ***M);
    void local_adjoit_curl(const grid3d_t *grid, int el, unsigned type, vector A, double ***M);

    void test_scalar_field(const grid3d_t *grid, unsigned type, double time, field3d *F, scalar s);
    void test_vector_field(const grid3d_t *grid, unsigned type, double time, field3d *F, vector v);

    void test_scalar(const grid3d_t *grid, unsigned type, scalar p, scalar s);
    void test_vector(const grid3d_t *grid, unsigned type, vector u, vector v);

    void test_grad_e1_in_e2(const grid3d_t *grid, unsigned type1, const scalar p,
        unsigned type2, vector g);
    void test_e1_in_div_e2(const grid3d_t *grid, unsigned type1, const scalar p,
        unsigned type2, vector g);
    void test_e1_in_grad_e2(const grid3d_t *grid, unsigned type1, const vector u,
        unsigned type2, scalar q);
    void test_div_e1_in_e2(const grid3d_t *grid, unsigned type1, const vector u,
        unsigned type2, scalar q);
    void test_advection_vector(const grid3d_t *grid, unsigned type, const vector a,
        const vector u, vector g);
    void test_adjoint_B_vector(const grid3d_t *grid, unsigned type, const vector a,
        vector u, vector g);
    void test_advection_scalar(const grid3d_t *grid, unsigned type, const vector a,
        const scalar u, scalar g);
    void test_advection_vector_D(const grid3d_t *grid, unsigned type, const vector a,
        const vector u, vector g);


    void test_grad_e1_in_grad_e2_scal(const grid3d_t *grid, unsigned type1, const scalar p,
        unsigned type2, scalar q);
    void test_grad_e1_in_grad_e2_vec(const grid3d_t *grid, unsigned type1, const vector u,
        unsigned type2, vector v);
    void test_curl_e1_in_curl_e2_vec(const grid3d_t *grid, unsigned type1, const vector u,
        unsigned type2, vector v);


    void interpolate_scalar_lagr(const grid3d_t *grid, unsigned type, double time, field3d *F, scalar s);
    void interpolate_vector_lagr(const grid3d_t *grid, unsigned type, double time, field3d *F, vector s);

    void apply_bc_dir_vector(const grid3d_t *grid, unsigned type, double time, bc_field3d *F, vector s);
    void apply_bc_dir_scalar(const grid3d_t *grid, unsigned type, double time, bc_field3d *F, scalar s);

    void div_free_bc(const grid3d_t *grid, unsigned type, unsigned on_bdry, vector u);


    void make_scal_mean_0(const grid3d_t *grid, unsigned type, scalar p);

    /*
     * double norm_div_l2(const grid3d_t *grid, unsigned type, vector v);
     * double int_u_dot_n(const grid3d_t *grid, unsigned type, vector *);
     */

    double norm_curl_vec(const grid3d_t *grid, unsigned type, vector v);
    double norm_div_vec(const grid3d_t *grid, unsigned type, vector v);
    double norm_grad_vec(const grid3d_t *grid, unsigned type, vector v);


    double norm_vec_diff_l2(const grid3d_t *grid, unsigned type, vector v1,
        vector v2);
    double norm_vec_diff_h1(const grid3d_t *grid, unsigned type, vector v1,
        vector v2);
    double norm_scal_diff_l2(const grid3d_t *grid, unsigned type, scalar v1,
        scalar v2);
    double norm_scal_diff_h1(const grid3d_t *grid, unsigned type, scalar v1,
        scalar v2);


#ifdef	__cplusplus
}
#endif

#endif	/* _FE_H */

